package com.pdfscan;

import com.google.zxing.*;
import com.google.zxing.client.j2se.BufferedImageLuminanceSource;
import com.google.zxing.common.HybridBinarizer;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;

public class PDFBarcodeScanner {
    private static final Logger logger = LoggerFactory.getLogger(PDFBarcodeScanner.class);
    private static final String OUTPUT_DIRECTORY = "output";

    public static void main(String[] args) {
        if (args.length < 1) {
            logger.error("请提供PDF文件路径作为参数");
            System.out.println("用法: java -jar pdf-barcode-scanner.jar <PDF文件路径>");
            return;
        }

        String pdfFilePath = args[0];
        File pdfFile = new File(pdfFilePath);
        
        if (!pdfFile.exists() || !pdfFile.isFile()) {
            logger.error("指定的PDF文件不存在: {}", pdfFilePath);
            return;
        }

        try {
            // 创建输出目录
            File outputDir = new File(OUTPUT_DIRECTORY);
            if (!outputDir.exists()) {
                outputDir.mkdir();
            }
            
            scanAndClassifyPdf(pdfFile);
            
        } catch (Exception e) {
            logger.error("处理PDF文件时发生错误", e);
        }
    }

    private static void scanAndClassifyPdf(File pdfFile) throws IOException {
        try (PDDocument document = PDDocument.load(pdfFile)) {
            PDFRenderer pdfRenderer = new PDFRenderer(document);
            int pageCount = document.getNumberOfPages();
            
            if (pageCount == 0) {
                logger.warn("PDF文件不包含任何页面");
                return;
            }
            
            logger.info("开始处理PDF文件: {}, 共 {} 页", pdfFile.getName(), pageCount);
            
            // 扫描所有页面的条形码
            List<String> barcodes = new ArrayList<>();
            for (int i = 0; i < pageCount; i++) {
                BufferedImage image = pdfRenderer.renderImageWithDPI(i, 300);
                String barcode = scanBarcodeFromImage(image);
                barcodes.add(barcode);
                logger.info("页面 {}: 条形码 {}", i + 1, barcode != null ? barcode : "未检测到");
            }
            
            // 按条形码分组页面
            Map<String, List<Integer>> barcodeGroups = classifyPagesByBarcode(barcodes);
            
            // 创建分组后的PDF文件
            createClassifiedPdfFiles(document, barcodeGroups, pdfFile.getName());
            
        } catch (IOException e) {
            logger.error("无法读取PDF文件", e);
            throw e;
        }
    }

    private static String scanBarcodeFromImage(BufferedImage image) {
        try {
            LuminanceSource source = new BufferedImageLuminanceSource(image);
            BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
            
            Map<DecodeHintType, Object> hints = new HashMap<>();
            hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE);
            hints.put(DecodeHintType.POSSIBLE_FORMATS, Arrays.asList(
                    BarcodeFormat.CODE_39,
                    BarcodeFormat.CODE_93, 
                    BarcodeFormat.CODE_128,
                    BarcodeFormat.EAN_8,
                    BarcodeFormat.EAN_13,
                    BarcodeFormat.QR_CODE,
                    BarcodeFormat.UPC_A,
                    BarcodeFormat.UPC_E,
                    BarcodeFormat.DATA_MATRIX));
            
            Result result = new MultiFormatReader().decode(bitmap, hints);
            return result.getText();
            
        } catch (NotFoundException e) {
            // 没有找到条形码，返回null
            return null;
        } catch (Exception e) {
            logger.error("扫描条形码时发生错误", e);
            return null;
        }
    }

    private static Map<String, List<Integer>> classifyPagesByBarcode(List<String> barcodes) {
        Map<String, List<Integer>> groups = new HashMap<>();
        
        if (barcodes.isEmpty()) {
            return groups;
        }
        
        // 获取第一个有效的条形码作为基准
        String firstBarcode = null;
        for (String barcode : barcodes) {
            if (barcode != null && !barcode.isEmpty()) {
                firstBarcode = barcode;
                break;
            }
        }
        
        // 如果没有有效的条形码，将所有页面归为一组
        if (firstBarcode == null) {
            List<Integer> allPages = new ArrayList<>();
            for (int i = 0; i < barcodes.size(); i++) {
                allPages.add(i);
            }
            groups.put("无条形码", allPages);
            return groups;
        }
        
        // 根据条形码分组页面
        for (int i = 0; i < barcodes.size(); i++) {
            String barcode = barcodes.get(i);
            
            // 如果页面没有条形码，使用默认分组
            if (barcode == null || barcode.isEmpty()) {
                barcode = "无条形码";
            }
            
            // 根据第一个条形码规则进行分组
            if (barcode.equals(firstBarcode) || barcode.equals("无条形码")) {
                groups.computeIfAbsent(firstBarcode, k -> new ArrayList<>()).add(i);
            } else {
                groups.computeIfAbsent(barcode, k -> new ArrayList<>()).add(i);
            }
        }
        
        return groups;
    }

    private static void createClassifiedPdfFiles(PDDocument originalDocument, 
                                                Map<String, List<Integer>> barcodeGroups,
                                                String originalFileName) throws IOException {
        String baseFileName = originalFileName.replaceAll("\\.pdf$", "");
        
        for (Map.Entry<String, List<Integer>> entry : barcodeGroups.entrySet()) {
            String barcode = entry.getKey();
            List<Integer> pageIndexes = entry.getValue();
            
            if (pageIndexes.isEmpty()) {
                continue;
            }
            
            try (PDDocument newDocument = new PDDocument()) {
                // 复制页面到新文档
                for (int pageIndex : pageIndexes) {
                    newDocument.addPage(originalDocument.getPage(pageIndex));
                }
                
                // 保存新文档
                String outputFileName = String.format("%s/%s_%s.pdf", 
                        OUTPUT_DIRECTORY, baseFileName, barcode);
                newDocument.save(outputFileName);
                logger.info("已创建分类文件: {}, 包含 {} 页", outputFileName, pageIndexes.size());
            }
        }
    }
} 